/**********************************
   * Learning practices
   *
   *文件名称:01homework.c
   *文件标识:
   *摘要:给图片打马赛克(标准IO)
   *
   *当前版本:1.0
   *作者:上官筱旭
   *完成日期:2022.5.3
   *********************************/
#include <head.h>
#include <stdlib.h>

typedef struct
{
    unsigned int img_size;//图片大小
    unsigned int img_width;//图片的宽
    unsigned int img_high;//图片的高
    unsigned int img_bitcount;//一个像素点占用的比特
}img_info_t;
typedef struct
{
    unsigned char b;
    unsigned char g;
    unsigned char r;
}point_t;

void get_image_info(FILE* fp, img_info_t* info)
{
    fseek(fp, 2, SEEK_SET);
    fread(&info->img_size, 1, 4, fp);//读取图片的大小信息
    fseek(fp, 18, SEEK_SET);
    fread(&info->img_width, 1, 4, fp);//读取图片的宽
    fread(&info->img_high, 1, 4, fp);//读取图片的高
    fseek(fp, 2, SEEK_CUR);
    fread(&info->img_bitcount, 1, 2, fp);
}

void show_image_info(img_info_t *info)
{
    printf("size = %d,width = %d,high = %d,bitcount = %d\n",
    info->img_size,info->img_width,info->img_high,info->img_bitcount);
}

void copy_image_file(FILE* sfp, FILE* dfp)
{
    int ret;
    char buf[1024] = { 0 };
    while(!(feof(sfp) || ferror(sfp)))
    {
        ret = fread(buf, 1, sizeof(buf), sfp);
        fwrite(buf, 1, ret, dfp);
    }
    
}

void set_image_mosaic(FILE* fp, img_info_t* info, int x, int y)
{
    int i = 0;//整体的高/10
    int j = 0;//整体的宽/10
    int k = 0;//马赛克块的高
    int w = 0;//马赛克块的宽
    point_t color = {0, 0, 0xff};
    //开辟临时修改图像的内存空间
    char *buffer = (char *)malloc((info->img_width)*(info->img_high)*3);
    //1.将图像信息读取出
    fseek(fp, 54, SEEK_SET);
    fread(buffer, 1, info->img_size-54, fp);
    //2.修改
    for(i=0;i<info->img_high/y;i++){
        for(j=0;j<info->img_width/x;j++){
            //读取小方块中最左上角的像素点
            color = *(point_t *)(buffer+(j*3*x)+(i*y*info->img_width*3));
            for(k=0;k<y;k++){
                for(w=0;w<x;w++){
                      *(point_t*)(buffer+w*3+(k*info->img_width*3)+
                      (j*3*x)+(i*y*info->img_width*3)) = color;
                }
            }
        }
    }
    //3.重新将图像写回去
    fseek(fp,54,SEEK_SET);
    fwrite(buffer,1,(info->img_size-54),fp);
}

int main(int argc, char const* argv[])
{
    FILE* sfp;
    FILE* dfp;
    int size = 0;
    img_info_t info;
    char new_name[20] = { 0 };

    if(argc != 2){
        fprintf(stderr,"input error,try again\n");
        fprintf(stderr,"usage:./a.out xxxx.bmp\n");
        return -1;
    }
    //1.打开并拷贝源文件
    if(NULL == (sfp = fopen(argv[1], "r")))
        PRINT_ERR("open error");

    snprintf(new_name,sizeof(new_name),"new_%s",argv[1]);//构造一个新图片名字的字符串  new_milaoshu.bmp

    if((dfp = fopen(new_name,"w+"))==NULL)//打开新图片，如果不存在就创建，如果存在就清空
        PRINT_ERR("open error");
    
    copy_image_file(sfp, dfp);//拷贝图片

    //2.获取图片前54个字节中有用的信息
    get_image_info(dfp,&info);
    show_image_info(&info);

    //3.尝试打马赛克
    //10,10:代表的是打马赛克每个小方块的大小
    //10*3= 30byte
    //10  = 10行
    set_image_mosaic(dfp,&info,20,20);

    //4.关闭源文件和目标文件
    fclose(sfp);   
    fclose(dfp); 

    return 0;
}